﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;

using SBPweb.RIA.Shared.Contracts.Events;

using SBPweb.RIA.Client.Contracts.Base;
using SBPweb.RIA.Client.Contracts.Controllers;
using SBPweb.RIA.Client.Controls.Base;
using SBPweb.RIA.Client.Controls.Extensions;

using SBPweb.PROvibe.Client.Core.Models;
using SBPweb.PROvibe.Client.Core.Services.ConfigurationProvider;

using SBPweb.PROvibe.Client.Library.Base;
using SBPweb.PROvibe.Client.Library.Controllers;
using SBPweb.PROvibe.Client.Library.Models;

using SBPweb.PROvibe.Shared.Library.Components;

namespace SBPweb.PROvibe.Client.Core.Controllers
{

    public class ConfigurationController : ControllerBase<IConfigurationModel, ConfigurationModel, IConfigurationController>, IConfigurationController
    {

        #region Fields

        private ConfigurationProviderServiceClient serviceClient = new ConfigurationProviderServiceClient();

        #endregion

        #region Constructor logic

        public ConfigurationController()
        {
            Model = new ConfigurationModel();

            serviceClient.FixEndpointAddress<IConfigurationProviderService>("services/dynamic");

            serviceClient.EnumerateAllSuitesCompleted += new EventHandler<EnumerateAllSuitesCompletedEventArgs>(serviceClient_EnumerateAllSuitesCompleted);
            serviceClient.EnumerateAllModulesCompleted += new EventHandler<EnumerateAllModulesCompletedEventArgs>(serviceClient_EnumerateAllModulesCompleted);
            serviceClient.EnumerateModulesOfSuiteCompleted += new EventHandler<EnumerateModulesOfSuiteCompletedEventArgs>(serviceClient_EnumerateModulesOfSuiteCompleted);
            serviceClient.GetCurrentSuiteCompleted += new EventHandler<GetCurrentSuiteCompletedEventArgs>(serviceClient_GetCurrentSuiteCompleted);
            serviceClient.SetCurrentSuiteCompleted += new EventHandler<AsyncCompletedEventArgs>(serviceClient_SetCurrentSuiteCompleted);
        }

        ~ConfigurationController()
        {
            serviceClient.EnumerateAllSuitesCompleted -= new EventHandler<EnumerateAllSuitesCompletedEventArgs>(serviceClient_EnumerateAllSuitesCompleted);
            serviceClient.EnumerateAllModulesCompleted -= new EventHandler<EnumerateAllModulesCompletedEventArgs>(serviceClient_EnumerateAllModulesCompleted);
            serviceClient.EnumerateModulesOfSuiteCompleted -= new EventHandler<EnumerateModulesOfSuiteCompletedEventArgs>(serviceClient_EnumerateModulesOfSuiteCompleted);
            serviceClient.GetCurrentSuiteCompleted -= new EventHandler<GetCurrentSuiteCompletedEventArgs>(serviceClient_GetCurrentSuiteCompleted);
            serviceClient.SetCurrentSuiteCompleted -= new EventHandler<AsyncCompletedEventArgs>(serviceClient_SetCurrentSuiteCompleted);
        }

        #endregion

        #region Properties

        internal ConfigurationModel model
        {
            get
            {
                return Model as ConfigurationModel;
            }
        }

        #endregion

        #region Methods

        public static void RegisterApplicationSingleton()
        {
            RegisterController(new ConfigurationController());
        }

        public void EnumerateAllSuites()
        {
            EnumerateAllSuites(null);
        }

        public void EnumerateAllSuites(AsyncRequestHandler<ReadOnlyCollection<ISuite>> completed)
        {
            serviceClient.EnumerateAllSuitesAsync(new AsyncRequestArgs<ReadOnlyCollection<ISuite>>(completed));
        }

        public void EnumerateAllModules()
        {
            EnumerateAllModules(null);
        }

        public void EnumerateAllModules(AsyncRequestHandler<ReadOnlyCollection<IModule>> completed)
        {
            serviceClient.EnumerateAllModulesAsync(new AsyncRequestArgs<ReadOnlyCollection<IModule>>(completed));
        }

        public void GetCurrentSuite()
        {
            GetCurrentSuite(null);
        }

        public void GetCurrentSuite(AsyncRequestHandler<ISuite> completed)
        {
            serviceClient.GetCurrentSuiteAsync(new AsyncRequestArgs<ISuite>(completed));
        }

        public void SetCurrentSuite(ISuite suite)
        {
            serviceClient.SetCurrentSuiteAsync(suite as Suite, suite as Suite);
        }

        public void SetCurrentSuite(ISuite suite, AsyncRequestHandler<ISuite> completed)
        {
            serviceClient.SetCurrentSuiteAsync(suite as Suite, new AsyncRequestArgs<ISuite>(completed, suite));
        }

        public void EnumerateModulesOfSuite()
        {
            EnumerateModulesOfSuite(Model.CurrentSuite);
        }

        public void EnumerateModulesOfSuite(AsyncRequestHandler<ReadOnlyCollection<IModule>> completed)
        {
            EnumerateModulesOfSuite(Model.CurrentSuite, completed);
        }

        public void EnumerateModulesOfSuite(ISuite suite)
        {
            EnumerateModulesOfSuite(suite, null);
        }
        
        public void EnumerateModulesOfSuite(ISuite suite, AsyncRequestHandler<ReadOnlyCollection<IModule>> completed)
        {
            serviceClient.EnumerateModulesOfSuiteAsync(suite as Suite, new AsyncRequestArgs<ReadOnlyCollection<IModule>>(completed, suite));
        }

        #endregion

        #region Event handlers

        private void serviceClient_EnumerateAllSuitesCompleted(object sender, EnumerateAllSuitesCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                throw e.Error;
            }
                        
            AsyncRequestArgs<ReadOnlyCollection<ISuite>> args = e.UserState as AsyncRequestArgs<ReadOnlyCollection<ISuite>>;
            if (args == null)
            {
                throw new ArgumentException("UserState was not of the correct AsyncRequestArgs generic type!");
            }

            foreach (Suite suite in e.Result)
            {
                model.allSuites.Add(suite);
            }

            args.RaiseCompletedEvent(this, model.AllSuites);
        }
        
        private void serviceClient_EnumerateAllModulesCompleted(object sender, EnumerateAllModulesCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                throw e.Error;
            }

            AsyncRequestArgs<ReadOnlyCollection<IModule>> args = e.UserState as AsyncRequestArgs<ReadOnlyCollection<IModule>>;
            if (args == null)
            {
                throw new ArgumentException("UserState was not of the correct AsyncRequestArgs generic type!");
            }

            foreach (Module module in e.Result)
            {
                model.allModules.Add(module);
            }

            args.RaiseCompletedEvent(this, model.AllModules);
        }

        private void serviceClient_EnumerateModulesOfSuiteCompleted(object sender, EnumerateModulesOfSuiteCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                throw e.Error;
            }

            AsyncRequestArgs<ReadOnlyCollection<IModule>> args = e.UserState as AsyncRequestArgs<ReadOnlyCollection<IModule>>;
            if (args == null)
            {
                throw new ArgumentException("UserState was not of the correct AsyncRequestArgs generic type!");
            }
            Suite suite = args.Arguments.Get<Suite>(0);

            foreach (Module module in e.Result)
            {
                suite.modules.Add(module);
            }

            args.RaiseCompletedEvent(this, suite.Modules);
        }
        
        private void serviceClient_GetCurrentSuiteCompleted(object sender, GetCurrentSuiteCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                throw e.Error;
            }

            AsyncRequestArgs<ISuite> args = e.UserState as AsyncRequestArgs<ISuite>;
            if (args == null)
            {
                throw new ArgumentException("UserState was not of the correct AsyncRequestArgs generic type!");
            }

            model.CurrentSuite = e.Result;

            args.RaiseCompletedEvent(this, e.Result);
        }

        private void serviceClient_SetCurrentSuiteCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                throw e.Error;
            }

            AsyncRequestArgs<ISuite> args = e.UserState as AsyncRequestArgs<ISuite>;
            if (args == null)
            {
                throw new ArgumentException("UserState was not of the correct AsyncRequestArgs generic type!");
            }
            Suite suite = args.Arguments.Get<Suite>(0);

            model.CurrentSuite = suite;

            args.RaiseCompletedEvent(this, suite);
        }

        #endregion

    }

}